home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 83 / MacAddict_083_2003-07.iso / mac / Software / Development / VLC Source 0.5.3.dmg / src / misc / objects.c < prev    next >
C/C++ Source or Header  |  2003-04-07  |  30KB  |  998 lines

  1. /*****************************************************************************
  2.  * objects.c: vlc_object_t handling
  3.  *****************************************************************************
  4.  * Copyright (C) 2002 VideoLAN
  5.  * $Id: objects.c,v 1.35 2003/02/23 19:07:02 fenrir Exp $
  6.  *
  7.  * Authors: Samuel Hocevar <sam@zoy.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23.  
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <vlc/vlc.h>
  28.  
  29. #ifdef HAVE_STDLIB_H
  30. #   include <stdlib.h>                                          /* realloc() */
  31. #endif
  32.  
  33. #include "stream_control.h"
  34. #include "input_ext-intf.h"
  35. #include "input_ext-dec.h"
  36.  
  37. #include "video.h"
  38. #include "video_output.h"
  39.  
  40. #include "audio_output.h"
  41. #include "aout_internal.h"
  42. #include "stream_output.h"
  43.  
  44. #include "vlc_playlist.h"
  45. #include "interface.h"
  46.  
  47. #include "httpd.h"
  48. /*****************************************************************************
  49.  * Local prototypes
  50.  *****************************************************************************/
  51. static int  DumpCommand( vlc_object_t *, char const *,
  52.                          vlc_value_t, vlc_value_t, void * );
  53.  
  54. static vlc_object_t * FindObject    ( vlc_object_t *, int, int );
  55. static void           DetachObject  ( vlc_object_t * );
  56. static void           PrintObject   ( vlc_object_t *, const char * );
  57. static void           DumpStructure ( vlc_object_t *, int, char * );
  58. static int            FindIndex     ( vlc_object_t *, vlc_object_t **, int );
  59. static void           SetAttachment ( vlc_object_t *, vlc_bool_t );
  60.  
  61. static vlc_list_t   * NewList       ( int );
  62. static void           ListReplace   ( vlc_list_t *, vlc_object_t *, int );
  63. static void           ListAppend    ( vlc_list_t *, vlc_object_t * );
  64. static int            CountChildren ( vlc_object_t *, int );
  65. static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
  66.  
  67. /*****************************************************************************
  68.  * Local structure lock
  69.  *****************************************************************************/
  70. static vlc_mutex_t    structure_lock;
  71.  
  72. /*****************************************************************************
  73.  * vlc_object_create: initialize a vlc object
  74.  *****************************************************************************
  75.  * This function allocates memory for a vlc object and initializes it. If
  76.  * i_type is not a known value such as VLC_OBJECT_ROOT, VLC_OBJECT_VOUT and
  77.  * so on, vlc_object_create will use its value for the object size.
  78.  *****************************************************************************/
  79. void * __vlc_object_create( vlc_object_t *p_this, int i_type )
  80. {
  81.     vlc_object_t * p_new;
  82.     char *         psz_type;
  83.     size_t         i_size;
  84.  
  85.     switch( i_type )
  86.     {
  87.         case VLC_OBJECT_ROOT:
  88.             i_size = sizeof(libvlc_t);
  89.             psz_type = "root";
  90.             break;
  91.         case VLC_OBJECT_VLC:
  92.             i_size = sizeof(vlc_t);
  93.             psz_type = "vlc";
  94.             break;
  95.         case VLC_OBJECT_MODULE:
  96.             i_size = sizeof(module_t);
  97.             psz_type = "module";
  98.             break;
  99.         case VLC_OBJECT_INTF:
  100.             i_size = sizeof(intf_thread_t);
  101.             psz_type = "interface";
  102.             break;
  103.         case VLC_OBJECT_PLAYLIST:
  104.             i_size = sizeof(playlist_t);
  105.             psz_type = "playlist";
  106.             break;
  107.         case VLC_OBJECT_INPUT:
  108.             i_size = sizeof(input_thread_t);
  109.             psz_type = "input";
  110.             break;
  111.         case VLC_OBJECT_DECODER:
  112.             i_size = sizeof(decoder_fifo_t);
  113.             psz_type = "decoder";
  114.             break;
  115.         case VLC_OBJECT_VOUT:
  116.             i_size = sizeof(vout_thread_t);
  117.             psz_type = "video output";
  118.             break;
  119.         case VLC_OBJECT_AOUT:
  120.             i_size = sizeof(aout_instance_t);
  121.             psz_type = "audio output";
  122.             break;
  123.         case VLC_OBJECT_SOUT:
  124.             i_size = sizeof(sout_instance_t);
  125.             psz_type = "stream output";
  126.             break;
  127.         case VLC_OBJECT_HTTPD:
  128.             i_size = sizeof( httpd_t );
  129.             psz_type = "http daemon";
  130.             break;
  131.         default:
  132.             i_size = i_type > 0
  133.                       ? i_type > (int)sizeof(vlc_object_t)
  134.                          ? i_type : (int)sizeof(vlc_object_t)
  135.                       : (int)sizeof(vlc_object_t);
  136.             i_type = VLC_OBJECT_GENERIC;
  137.             psz_type = "generic";
  138.             break;
  139.     }
  140.  
  141.     if( i_type == VLC_OBJECT_ROOT )
  142.     {
  143.         p_new = p_this;
  144.     }
  145.     else
  146.     {
  147.         p_new = malloc( i_size );
  148.  
  149.         if( !p_new )
  150.         {
  151.             return NULL;
  152.         }
  153.  
  154.         memset( p_new, 0, i_size );
  155.     }
  156.  
  157.     p_new->i_object_type = i_type;
  158.     p_new->psz_object_type = psz_type;
  159.  
  160.     p_new->psz_object_name = NULL;
  161.  
  162.     p_new->b_die = VLC_FALSE;
  163.     p_new->b_error = VLC_FALSE;
  164.     p_new->b_dead = VLC_FALSE;
  165.     p_new->b_attached = VLC_FALSE;
  166.  
  167.     p_new->i_vars = 0;
  168.     p_new->p_vars = (variable_t *)malloc( 16 * sizeof( variable_t ) );
  169.  
  170.     if( !p_new->p_vars )
  171.     {
  172.         free( p_new );
  173.         return NULL;
  174.     }
  175.  
  176.     if( i_type == VLC_OBJECT_ROOT )
  177.     {
  178.         /* If i_type is root, then p_new is actually p_libvlc */
  179.         p_new->p_libvlc = (libvlc_t*)p_new;
  180.         p_new->p_vlc = NULL;
  181.  
  182.         p_new->p_libvlc->i_counter = 0;
  183.         p_new->i_object_id = 0;
  184.  
  185.         p_new->p_libvlc->i_objects = 1;
  186.         p_new->p_libvlc->pp_objects = malloc( sizeof(vlc_object_t *) );
  187.         p_new->p_libvlc->pp_objects[0] = p_new;
  188.         p_new->b_attached = VLC_TRUE;
  189.     }
  190.     else
  191.     {
  192.         p_new->p_libvlc = p_this->p_libvlc;
  193.         p_new->p_vlc = ( i_type == VLC_OBJECT_VLC ) ? (vlc_t*)p_new
  194.                                                     : p_this->p_vlc;
  195.  
  196.         vlc_mutex_lock( &structure_lock );
  197.  
  198.         p_new->p_libvlc->i_counter++;
  199.         p_new->i_object_id = p_new->p_libvlc->i_counter;
  200.  
  201.         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
  202.          * useless to try and recover anything if pp_objects gets smashed. */
  203.         INSERT_ELEM( p_new->p_libvlc->pp_objects,
  204.                      p_new->p_libvlc->i_objects,
  205.                      p_new->p_libvlc->i_objects,
  206.                      p_new );
  207.  
  208.         vlc_mutex_unlock( &structure_lock );
  209.     }
  210.  
  211.     p_new->i_refcount = 0;
  212.     p_new->p_parent = NULL;
  213.     p_new->pp_children = NULL;
  214.     p_new->i_children = 0;
  215.  
  216.     p_new->p_private = NULL;
  217.  
  218.     /* Initialize mutexes and condvars */
  219.     vlc_mutex_init( p_new, &p_new->object_lock );
  220.     vlc_cond_init( p_new, &p_new->object_wait );
  221.     vlc_mutex_init( p_new, &p_new->var_lock );
  222.  
  223.     if( i_type == VLC_OBJECT_ROOT )
  224.     {
  225.         vlc_mutex_init( p_new, &structure_lock );
  226.  
  227.         var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
  228.         var_AddCallback( p_new, "list", DumpCommand, NULL );
  229.         var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
  230.         var_AddCallback( p_new, "tree", DumpCommand, NULL );
  231.     }
  232.  
  233.     return p_new;
  234. }
  235.  
  236. /*****************************************************************************
  237.  * vlc_object_destroy: destroy a vlc object
  238.  *****************************************************************************
  239.  * This function destroys an object that has been previously allocated with
  240.  * vlc_object_create. The object's refcount must be zero and it must not be
  241.  * attached to other objects in any way.
  242.  *****************************************************************************/
  243. void __vlc_object_destroy( vlc_object_t *p_this )
  244. {
  245.     int i_delay = 0;
  246.  
  247.     if( p_this->i_children )
  248.     {
  249.         msg_Err( p_this, "cannot delete object with children" );
  250.         return;
  251.     }
  252.  
  253.     if( p_this->p_parent )
  254.     {
  255.         msg_Err( p_this, "cannot delete object with a parent" );
  256.         return;
  257.     }
  258.  
  259.     while( p_this->i_refcount )
  260.     {
  261.         i_delay++;
  262.  
  263.         /* Don't warn immediately ... 100ms seems OK */
  264.         if( i_delay == 2 )
  265.         {
  266.             msg_Warn( p_this, "refcount is %i, delaying before deletion",
  267.                               p_this->i_refcount );
  268.         }
  269.         else if( i_delay == 12 )
  270.         {
  271.             msg_Err( p_this, "refcount is %i, I have a bad feeling about this",
  272.                              p_this->i_refcount );
  273.         }
  274.         else if( i_delay == 42 )
  275.         {
  276.             msg_Err( p_this, "we waited too long, cancelling destruction" );
  277.             return;
  278.         }
  279.  
  280.         msleep( 100000 );
  281.     }
  282.  
  283.     /* Destroy the associated variables, starting from the end so that
  284.      * no memmove calls have to be done. */
  285.     while( p_this->i_vars )
  286.     {
  287.         var_Destroy( p_this, p_this->p_vars[p_this->i_vars - 1].psz_name );
  288.     }
  289.  
  290.     free( p_this->p_vars );
  291.     vlc_mutex_destroy( &p_this->var_lock );
  292.  
  293.     if( p_this->i_object_type == VLC_OBJECT_ROOT )
  294.     {
  295.         /* We are the root object ... no need to lock. */
  296.         free( p_this->p_libvlc->pp_objects );
  297.         p_this->p_libvlc->pp_objects = NULL;
  298.         p_this->p_libvlc->i_objects--;
  299.  
  300.         vlc_mutex_destroy( &structure_lock );
  301.     }
  302.     else
  303.     {
  304.         int i_index;
  305.  
  306.         vlc_mutex_lock( &structure_lock );
  307.  
  308.         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
  309.          * useless to try and recover anything if pp_objects gets smashed. */
  310.         i_index = FindIndex( p_this, p_this->p_libvlc->pp_objects,
  311.                              p_this->p_libvlc->i_objects );
  312.         REMOVE_ELEM( p_this->p_libvlc->pp_objects,
  313.                      p_this->p_libvlc->i_objects, i_index );
  314.  
  315.         vlc_mutex_unlock( &structure_lock );
  316.     }
  317.  
  318.     vlc_mutex_destroy( &p_this->object_lock );
  319.     vlc_cond_destroy( &p_this->object_wait );
  320.  
  321.     free( p_this );
  322. }
  323.  
  324. /*****************************************************************************
  325.  * vlc_object_get: find an object given its ID
  326.  *****************************************************************************
  327.  * This function looks for the object whose i_object_id field is i_id. We
  328.  * use a dichotomy so that lookups are in log2(n).
  329.  *****************************************************************************/
  330. void * __vlc_object_get( vlc_object_t *p_this, int i_id )
  331. {
  332.     int i_max, i_middle;
  333.     vlc_object_t **pp_objects;
  334.  
  335.     vlc_mutex_lock( &structure_lock );
  336.  
  337.     pp_objects = p_this->p_libvlc->pp_objects;
  338.  
  339.     /* Perform our dichotomy */
  340.     for( i_max = p_this->p_libvlc->i_objects - 1 ; ; )
  341.     {
  342.         i_middle = i_max / 2;
  343.  
  344.         if( pp_objects[i_middle]->i_object_id > i_id )
  345.         {
  346.             i_max = i_middle;
  347.         }
  348.         else if( pp_objects[i_middle]->i_object_id < i_id )
  349.         {
  350.             if( i_middle )
  351.             {
  352.                 pp_objects += i_middle;
  353.                 i_max -= i_middle;
  354.             }
  355.             else
  356.             {
  357.                 /* This happens when there are only two remaining objects */
  358.                 if( pp_objects[i_middle+1]->i_object_id == i_id )
  359.                 {
  360.                     vlc_mutex_unlock( &structure_lock );
  361.                     pp_objects[i_middle+1]->i_refcount++;
  362.                     return pp_objects[i_middle+1];
  363.                 }
  364.                 break;
  365.             }
  366.         }
  367.         else
  368.         {
  369.             vlc_mutex_unlock( &structure_lock );
  370.             pp_objects[i_middle]->i_refcount++;
  371.             return pp_objects[i_middle];
  372.         }
  373.  
  374.         if( i_max == 0 )
  375.         {
  376.             /* this means that i_max == i_middle, and since we have already
  377.              * tested pp_objects[i_middle]), p_found is properly set. */
  378.             break;
  379.         }
  380.     }
  381.  
  382.     vlc_mutex_unlock( &structure_lock );
  383.     return NULL;
  384. }
  385.  
  386. /*****************************************************************************
  387.  * vlc_object_find: find a typed object and increment its refcount
  388.  *****************************************************************************
  389.  * This function recursively looks for a given object type. i_mode can be one
  390.  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
  391.  *****************************************************************************/
  392. void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
  393. {
  394.     vlc_object_t *p_found;
  395.  
  396.     vlc_mutex_lock( &structure_lock );
  397.  
  398.     /* If we are of the requested type ourselves, don't look further */
  399.     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
  400.     {
  401.         p_this->i_refcount++;
  402.         vlc_mutex_unlock( &structure_lock );
  403.         return p_this;
  404.     }
  405.  
  406.     /* Otherwise, recursively look for the object */
  407.     if( (i_mode & 0x000f) == FIND_ANYWHERE )
  408.     {
  409.         p_found = FindObject( VLC_OBJECT(p_this->p_vlc), i_type,
  410.                               (i_mode & ~0x000f) | FIND_CHILD );
  411.     }
  412.     else
  413.     {
  414.         p_found = FindObject( p_this, i_type, i_mode );
  415.     }
  416.  
  417.     vlc_mutex_unlock( &structure_lock );
  418.  
  419.     return p_found;
  420. }
  421.  
  422. /*****************************************************************************
  423.  * vlc_object_yield: increment an object refcount
  424.  *****************************************************************************/
  425. void __vlc_object_yield( vlc_object_t *p_this )
  426. {
  427.     vlc_mutex_lock( &structure_lock );
  428.     p_this->i_refcount++;
  429.     vlc_mutex_unlock( &structure_lock );
  430. }
  431.  
  432. /*****************************************************************************
  433.  * vlc_object_release: decrement an object refcount
  434.  *****************************************************************************/
  435. void __vlc_object_release( vlc_object_t *p_this )
  436. {
  437.     vlc_mutex_lock( &structure_lock );
  438.     p_this->i_refcount--;
  439.     vlc_mutex_unlock( &structure_lock );
  440. }
  441.  
  442. /*****************************************************************************
  443.  * vlc_object_attach: attach object to a parent object
  444.  *****************************************************************************
  445.  * This function sets p_this as a child of p_parent, and p_parent as a parent
  446.  * of p_this. This link can be undone using vlc_object_detach.
  447.  *****************************************************************************/
  448. void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
  449. {
  450.     vlc_mutex_lock( &structure_lock );
  451.  
  452.     /* Attach the parent to its child */
  453.     p_this->p_parent = p_parent;
  454.  
  455.     /* Attach the child to its parent */
  456.     INSERT_ELEM( p_parent->pp_children, p_parent->i_children,
  457.                  p_parent->i_children, p_this );
  458.  
  459.     /* Climb up the tree to see whether we are connected with the root */
  460.     if( p_parent->b_attached )
  461.     {
  462.         SetAttachment( p_this, VLC_TRUE );
  463.     }
  464.  
  465.     vlc_mutex_unlock( &structure_lock );
  466. }
  467.  
  468. /*****************************************************************************
  469.  * vlc_object_detach: detach object from its parent
  470.  *****************************************************************************
  471.  * This function removes all links between an object and its parent.
  472.  *****************************************************************************/
  473. void __vlc_object_detach( vlc_object_t *p_this )
  474. {
  475.     vlc_mutex_lock( &structure_lock );
  476.     if( !p_this->p_parent )
  477.     {
  478.         msg_Err( p_this, "object is not attached" );
  479.         vlc_mutex_unlock( &structure_lock );
  480.         return;
  481.     }
  482.  
  483.     /* Climb up the tree to see whether we are connected with the root */
  484.     if( p_this->p_parent->b_attached )
  485.     {
  486.         SetAttachment( p_this, VLC_FALSE );
  487.     }
  488.  
  489.     DetachObject( p_this );
  490.     vlc_mutex_unlock( &structure_lock );
  491. }
  492.  
  493. /*****************************************************************************
  494.  * vlc_list_find: find a list typed objects and increment their refcount
  495.  *****************************************************************************
  496.  * This function recursively looks for a given object type. i_mode can be one
  497.  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
  498.  *****************************************************************************/
  499. vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
  500. {
  501.     vlc_list_t *p_list;
  502.     vlc_object_t **pp_current, **pp_end;
  503.     int i_count = 0, i_index = 0;
  504.  
  505.     vlc_mutex_lock( &structure_lock );
  506.  
  507.     /* Look for the objects */
  508.     switch( i_mode & 0x000f )
  509.     {
  510.     case FIND_ANYWHERE:
  511.         pp_current = p_this->p_libvlc->pp_objects;
  512.         pp_end = pp_current + p_this->p_libvlc->i_objects;
  513.  
  514.         for( ; pp_current < pp_end ; pp_current++ )
  515.         {
  516.             if( (*pp_current)->b_attached
  517.                  && (*pp_current)->i_object_type == i_type )
  518.             {
  519.                 i_count++;
  520.             }
  521.         }
  522.  
  523.         p_list = NewList( i_count );
  524.         pp_current = p_this->p_libvlc->pp_objects;
  525.  
  526.         for( ; pp_current < pp_end ; pp_current++ )
  527.         {
  528.             if( (*pp_current)->b_attached
  529.                  && (*pp_current)->i_object_type == i_type )
  530.             {
  531.                 ListReplace( p_list, *pp_current, i_index );
  532.                 if( i_index < i_count ) i_index++;
  533.             }
  534.         }
  535.     break;
  536.  
  537.     case FIND_CHILD:
  538.         i_count = CountChildren( p_this, i_type );
  539.         p_list = NewList( i_count );
  540.  
  541.         /* Check allocation was successful */
  542.         if( p_list->i_count != i_count )
  543.         {
  544.             msg_Err( p_this, "list allocation failed!" );
  545.             p_list->i_count = 0;
  546.             break;
  547.         }
  548.  
  549.         p_list->i_count = 0;
  550.         ListChildren( p_list, p_this, i_type );
  551.         break;
  552.  
  553.     default:
  554.         msg_Err( p_this, "unimplemented!" );
  555.         p_list = NewList( 0 );
  556.         break;
  557.     }
  558.  
  559.     vlc_mutex_unlock( &structure_lock );
  560.  
  561.     return p_list;
  562. }
  563.  
  564. /*****************************************************************************
  565.  * DumpCommand: print the current vlc structure
  566.  *****************************************************************************
  567.  * This function prints either an ASCII tree showing the connections between
  568.  * vlc objects, and additional information such as their refcount, thread ID,
  569.  * etc. (command "tree"), or the same data as a simple list (command "list").
  570.  *****************************************************************************/
  571. static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
  572.                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
  573. {
  574.     if( *psz_cmd == 't' )
  575.     {
  576.         char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
  577.         vlc_object_t *p_object;
  578.  
  579.         if( *newval.psz_string )
  580.         {
  581.             p_object = vlc_object_get( p_this, atoi(newval.psz_string) );
  582.  
  583.             if( !p_object )
  584.             {
  585.                 return VLC_ENOOBJ;
  586.             }
  587.         }
  588.         else
  589.         {
  590.             p_object = p_this->p_vlc ? VLC_OBJECT(p_this->p_vlc) : p_this;
  591.         }
  592.  
  593.         vlc_mutex_lock( &structure_lock );
  594.  
  595.         psz_foo[0] = '|';
  596.         DumpStructure( p_object, 0, psz_foo );
  597.  
  598.         vlc_mutex_unlock( &structure_lock );
  599.  
  600.         if( *newval.psz_string )
  601.         {
  602.             vlc_object_release( p_this );
  603.         }
  604.     }
  605.     else if( *psz_cmd == 'l' )
  606.     {
  607.         vlc_object_t **pp_current, **pp_end;
  608.  
  609.         vlc_mutex_lock( &structure_lock );
  610.  
  611.         pp_current = p_this->p_libvlc->pp_objects;
  612.         pp_end = pp_current + p_this->p_libvlc->i_objects;
  613.  
  614.         for( ; pp_current < pp_end ; pp_current++ )
  615.         {
  616.             if( (*pp_current)->b_attached )
  617.             {
  618.                 PrintObject( *pp_current, "" );
  619.             }
  620.             else
  621.             {
  622.                 printf( " o %.8i %s (not attached)\n",
  623.                         (*pp_current)->i_object_id,
  624.                         (*pp_current)->psz_object_type );
  625.             }
  626.         }
  627.  
  628.         vlc_mutex_unlock( &structure_lock );
  629.     }
  630.  
  631.     return VLC_SUCCESS;
  632. }
  633.  
  634. /*****************************************************************************
  635.  * vlc_list_release: free a list previously allocated by vlc_list_find
  636.  *****************************************************************************
  637.  * This function decreases the refcount of all objects in the list and
  638.  * frees the list.
  639.  *****************************************************************************/
  640. void vlc_list_release( vlc_list_t *p_list )
  641. {
  642.     int i_index;
  643.  
  644.     for( i_index = 0; i_index < p_list->i_count; i_index++ )
  645.     {
  646.         vlc_mutex_lock( &structure_lock );
  647.  
  648.         p_list->p_values[i_index].p_object->i_refcount--;
  649.  
  650.         vlc_mutex_unlock( &structure_lock );
  651.     }
  652.  
  653.     free( p_list->p_values );
  654.     free( p_list );
  655. }
  656.  
  657. /* Following functions are local */
  658.  
  659. /*****************************************************************************
  660.  * FindIndex: find the index of an object in an array of objects
  661.  *****************************************************************************
  662.  * This function assumes that p_this can be found in pp_objects. It will not
  663.  * crash if p_this cannot be found, but will return a wrong value. It is your
  664.  * duty to check the return value if you are not certain that the object could
  665.  * be found for sure.
  666.  *****************************************************************************/
  667. static int FindIndex( vlc_object_t *p_this,
  668.                       vlc_object_t **pp_objects, int i_count )
  669. {
  670.     int i_middle = i_count / 2;
  671.  
  672.     if( i_count == 0 )
  673.     {
  674.         return 0;
  675.     }
  676.  
  677.     if( pp_objects[i_middle] == p_this )
  678.     {
  679.         return i_middle;
  680.     }
  681.  
  682.     if( i_count == 1 )
  683.     {
  684.         return 0;
  685.     }
  686.  
  687.     /* We take advantage of the sorted array */
  688.     if( pp_objects[i_middle]->i_object_id < p_this->i_object_id )
  689.     {
  690.         return i_middle + FindIndex( p_this, pp_objects + i_middle,
  691.                                              i_count - i_middle );
  692.     }
  693.     else
  694.     {
  695.         return FindIndex( p_this, pp_objects, i_middle );
  696.     }
  697. }
  698.  
  699. static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
  700. {
  701.     int i;
  702.     vlc_object_t *p_tmp;
  703.  
  704.     switch( i_mode & 0x000f )
  705.     {
  706.     case FIND_PARENT:
  707.         p_tmp = p_this->p_parent;
  708.         if( p_tmp )
  709.         {
  710.             if( p_tmp->i_object_type == i_type )
  711.             {
  712.                 p_tmp->i_refcount++;
  713.                 return p_tmp;
  714.             }
  715.             else
  716.             {
  717.                 return FindObject( p_tmp, i_type, i_mode );
  718.             }
  719.         }
  720.         break;
  721.  
  722.     case FIND_CHILD:
  723.         for( i = p_this->i_children; i--; )
  724.         {
  725.             p_tmp = p_this->pp_children[i];
  726.             if( p_tmp->i_object_type == i_type )
  727.             {
  728.                 p_tmp->i_refcount++;
  729.                 return p_tmp;
  730.             }
  731.             else if( p_tmp->i_children )
  732.             {
  733.                 p_tmp = FindObject( p_tmp, i_type, i_mode );
  734.                 if( p_tmp )
  735.                 {
  736.                     return p_tmp;
  737.                 }
  738.             }
  739.         }
  740.         break;
  741.  
  742.     case FIND_ANYWHERE:
  743.         /* Handled in vlc_object_find */
  744.         break;
  745.     }
  746.  
  747.     return NULL;
  748. }
  749.  
  750. static void DetachObject( vlc_object_t *p_this )
  751. {
  752.     vlc_object_t *p_parent = p_this->p_parent;
  753.     int i_index, i;
  754.  
  755.     /* Remove p_this's parent */
  756.     p_this->p_parent = NULL;
  757.  
  758.     /* Remove all of p_parent's children which are p_this */
  759.     for( i_index = p_parent->i_children ; i_index-- ; )
  760.     {
  761.         if( p_parent->pp_children[i_index] == p_this )
  762.         {
  763.             p_parent->i_children--;
  764.             for( i = i_index ; i < p_parent->i_children ; i++ )
  765.             {
  766.                 p_parent->pp_children[i] = p_parent->pp_children[i+1];
  767.             }
  768.         }
  769.     }
  770.  
  771.     if( p_parent->i_children )
  772.     {
  773.         p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
  774.                                p_parent->i_children * sizeof(vlc_object_t *) );
  775.     }
  776.     else
  777.     {
  778.         free( p_parent->pp_children );
  779.         p_parent->pp_children = NULL;
  780.     }
  781. }
  782.  
  783. /*****************************************************************************
  784.  * SetAttachment: recursively set the b_attached flag of a subtree.
  785.  *****************************************************************************
  786.  * This function is used by the attach and detach functions to propagate
  787.  * the b_attached flag in a subtree.
  788.  *****************************************************************************/
  789. static void SetAttachment( vlc_object_t *p_this, vlc_bool_t b_attached )
  790. {
  791.     int i_index;
  792.  
  793.     for( i_index = p_this->i_children ; i_index-- ; )
  794.     {
  795.         SetAttachment( p_this->pp_children[i_index], b_attached );
  796.     }
  797.  
  798.     p_this->b_attached = b_attached;
  799. }
  800.  
  801. static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
  802. {
  803.     char psz_children[20], psz_refcount[20], psz_thread[20], psz_name[50];
  804.  
  805.     psz_name[0] = '\0';
  806.     if( p_this->psz_object_name )
  807.     {
  808.         snprintf( psz_name, 50, " \"%s\"", p_this->psz_object_name );
  809.         psz_name[48] = '\"';
  810.         psz_name[49] = '\0';
  811.     }
  812.  
  813.     psz_children[0] = '\0';
  814.     switch( p_this->i_children )
  815.     {
  816.         case 0:
  817.             break;
  818.         case 1:
  819.             strcpy( psz_children, ", 1 child" );
  820.             break;
  821.         default:
  822.             snprintf( psz_children, 20,
  823.                       ", %i children", p_this->i_children );
  824.             psz_children[19] = '\0';
  825.             break;
  826.     }
  827.  
  828.     psz_refcount[0] = '\0';
  829.     if( p_this->i_refcount )
  830.     {
  831.         snprintf( psz_refcount, 20, ", refcount %i", p_this->i_refcount );
  832.         psz_refcount[19] = '\0';
  833.     }
  834.  
  835.     psz_thread[0] = '\0';
  836.     if( p_this->b_thread )
  837.     {
  838.         snprintf( psz_thread, 20, " (thread %d)", (int)p_this->thread_id );
  839.         psz_thread[19] = '\0';
  840.     }
  841.  
  842.     printf( " %so %.8i %s%s%s%s%s\n", psz_prefix,
  843.             p_this->i_object_id, p_this->psz_object_type,
  844.             psz_name, psz_thread, psz_refcount, psz_children );
  845. }
  846.  
  847. static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
  848. {
  849.     int i;
  850.     char i_back = psz_foo[i_level];
  851.     psz_foo[i_level] = '\0';
  852.  
  853.     PrintObject( p_this, psz_foo );
  854.  
  855.     psz_foo[i_level] = i_back;
  856.  
  857.     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
  858.     {
  859.         msg_Warn( p_this, "structure tree is too deep" );
  860.         return;
  861.     }
  862.  
  863.     for( i = 0 ; i < p_this->i_children ; i++ )
  864.     {
  865.         if( i_level )
  866.         {
  867.             psz_foo[i_level-1] = ' ';
  868.  
  869.             if( psz_foo[i_level-2] == '`' )
  870.             {
  871.                 psz_foo[i_level-2] = ' ';
  872.             }
  873.         }
  874.  
  875.         if( i == p_this->i_children - 1 )
  876.         {
  877.             psz_foo[i_level] = '`';
  878.         }
  879.         else
  880.         {
  881.             psz_foo[i_level] = '|';
  882.         }
  883.  
  884.         psz_foo[i_level+1] = '-';
  885.         psz_foo[i_level+2] = '\0';
  886.  
  887.         DumpStructure( p_this->pp_children[i], i_level + 2, psz_foo );
  888.     }
  889. }
  890.  
  891. static vlc_list_t * NewList( int i_count )
  892. {
  893.     vlc_list_t * p_list = (vlc_list_t *)malloc( sizeof( vlc_list_t ) );
  894.     if( p_list == NULL )
  895.     {
  896.         return NULL;
  897.     }
  898.  
  899.     p_list->i_count = i_count;
  900.  
  901.     if( i_count == 0 )
  902.     {
  903.         p_list->p_values = NULL;
  904.         return p_list;
  905.     }
  906.  
  907.     p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
  908.     if( p_list->p_values == NULL )
  909.     {
  910.         p_list->i_count = 0;
  911.         return p_list;
  912.     }
  913.  
  914.     return p_list;
  915. }
  916.  
  917. static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
  918.                          int i_index )
  919. {
  920.     if( p_list == NULL || i_index >= p_list->i_count )
  921.     {
  922.         return;
  923.     }
  924.  
  925.     p_object->i_refcount++;
  926.  
  927.     p_list->p_values[i_index].p_object = p_object;
  928.  
  929.     return;
  930. }
  931.  
  932. static void ListAppend( vlc_list_t *p_list, vlc_object_t *p_object )
  933. {
  934.     if( p_list == NULL )
  935.     {
  936.         return;
  937.     }
  938.  
  939.     p_list->p_values = realloc( p_list->p_values, (p_list->i_count + 1)
  940.                                 * sizeof( vlc_value_t ) );
  941.     if( p_list->p_values == NULL )
  942.     {
  943.         p_list->i_count = 0;
  944.         return;
  945.     }
  946.  
  947.     p_object->i_refcount++;
  948.  
  949.     p_list->p_values[p_list->i_count].p_object = p_object;
  950.     p_list->i_count++;
  951.  
  952.     return;
  953. }
  954.  
  955. static int CountChildren( vlc_object_t *p_this, int i_type )
  956. {
  957.     vlc_object_t *p_tmp;
  958.     int i, i_count = 0;
  959.  
  960.     for( i = 0; i < p_this->i_children; i++ )
  961.     {
  962.         p_tmp = p_this->pp_children[i];
  963.  
  964.         if( p_tmp->i_object_type == i_type )
  965.         {
  966.             i_count++;
  967.         }
  968.  
  969.         if( p_tmp->i_children )
  970.         {
  971.             i_count += CountChildren( p_tmp, i_type );
  972.         }
  973.     }
  974.  
  975.     return i_count;
  976. }
  977.  
  978. static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
  979. {
  980.     vlc_object_t *p_tmp;
  981.     int i;
  982.  
  983.     for( i = 0; i < p_this->i_children; i++ )
  984.     {
  985.         p_tmp = p_this->pp_children[i];
  986.  
  987.         if( p_tmp->i_object_type == i_type )
  988.         {
  989.             ListReplace( p_list, p_tmp, p_list->i_count++ );
  990.         }
  991.  
  992.         if( p_tmp->i_children )
  993.         {
  994.             ListChildren( p_list, p_tmp, i_type );
  995.         }
  996.     }
  997. }
  998.